﻿using System;
using System.Collections.Generic;
using System.IO;

namespace MalaCSharp
{
    ///-------------------------------------------------------------------------------------------------
    /// <summary> Mala game list. </summary>
    ///-------------------------------------------------------------------------------------------------
    public class MalaGameList
    {
        #region Properties

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the name. </summary>
        /// <value> The name. </value>
        ///-------------------------------------------------------------------------------------------------
        public String Name { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the author. </summary>
        /// <value> The author. </value>
        ///-------------------------------------------------------------------------------------------------
        public String Author { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the comment. </summary>
        /// <value> The comment. </value>
        ///-------------------------------------------------------------------------------------------------
        public String Comment { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the creation time. </summary>
        /// <value> The creation. </value>
        ///-------------------------------------------------------------------------------------------------
        public DateTime Creation { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the modification time. </summary>
        /// <value> The modification. </value>
        ///-------------------------------------------------------------------------------------------------
        public DateTime Modification { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets a value indicating whether list is write protected. </summary>
        /// <value> True if write protected, false if not. </value>
        ///-------------------------------------------------------------------------------------------------
        public bool WriteProtected { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the sort field. </summary>
        /// <value> The sort field. </value>
        ///-------------------------------------------------------------------------------------------------
        public Int32 SortField { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the games. </summary>
        /// <value> The games. </value>
        ///-------------------------------------------------------------------------------------------------
        public List<MalaGame> Games { get; private set; }

        #endregion

        #region Constructor(s)

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Default constructor. </summary>
        ///-------------------------------------------------------------------------------------------------
        public MalaGameList()
        {
            Name = "";
            Author = "";
            Comment = "";
            Creation = DateTime.MinValue;
            Modification = DateTime.MinValue;
            WriteProtected = false;
            SortField = 0;

            Games = new List<MalaGame>();
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Serves as a hash function for a particular type. </summary>
        /// <returns> A hash code for the current <see cref="T:System.Object" />. </returns>
        ///-------------------------------------------------------------------------------------------------
        public override int GetHashCode()
        {
            if (Name == null)
                return base.GetHashCode();
            else
                return Name.GetHashCode();
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Determines whether the specified <see cref="T:System.Object" /> is equal to the
        /// current <see cref="T:System.Object" />. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are null. </exception>
        /// <param name="obj"> The <see cref="T:System.Object" /> to compare with the current
        /// <see cref="T:System.Object" />. </param>
        /// <returns> true if the specified <see cref="T:System.Object" /> is equal to the current
        /// <see cref="T:System.Object" />; otherwise, false. </returns>
        ///-------------------------------------------------------------------------------------------------
        public override bool Equals(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");
            else
            {
                MalaGameList gameList = obj as MalaGameList;
                if (gameList == null)
                    return false;
                else
                    return Equals(gameList);
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Tests if this MalaGameList is considered equal to another. </summary>
        /// <param name="gameList"> The mala game list to compare to this object. </param>
        /// <returns> true if the objects are considered equal, false if they are not. </returns>
        ///-------------------------------------------------------------------------------------------------
        public bool Equals(MalaGameList gameList)
        {
            if (!Name.Equals(gameList.Name, StringComparison.Ordinal))
                return false;

            if (!Author.Equals(gameList.Author, StringComparison.Ordinal))
                return false;

            if (!Comment.Equals(gameList.Comment, StringComparison.Ordinal))
                return false;

            if (Creation != gameList.Creation)
                return false;

            if (Modification != gameList.Modification)
                return false;

            if (WriteProtected != gameList.WriteProtected)
                return false;

            if (SortField != gameList.SortField)
                return false;

            if (Games.Count != gameList.Games.Count)
                return false;

            for (int i = 0; i < Games.Count; i++)
                if (!Games[i].Equals(gameList.Games[i]))
                    return false;

            return true;
        }

        #endregion

        #region Public

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Saves header and games to the specified file. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are null. </exception>
        /// <param name="filePath"> Full pathname of the file to save to. </param>
        ///-------------------------------------------------------------------------------------------------
        public void Save(String filePath)
        {
            if (filePath == null)
                throw new ArgumentNullException("filePath");

            using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                StorageHelper.WriteListBegin(stream);

                StorageHelper.WriteString(stream, Name);
                StorageHelper.WriteString(stream, Author);
                StorageHelper.WriteString(stream, Comment);
                StorageHelper.WriteDate(stream, Creation);
                StorageHelper.WriteDate(stream, Modification);
                StorageHelper.WriteBool(stream, WriteProtected);

                StorageHelper.WriteInt(stream, Games.Count);

                StorageHelper.WriteInt(stream, SortField);

                StorageHelper.WriteListEnd(stream);

                foreach (MalaGame game in Games)
                    game.Save(stream);
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Loads from the specified file. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when filePath is null. </exception>
        /// <exception cref="FileNotFoundException"> Thrown when the requested file is not present. </exception>
        /// <param name="filePath"> Full pathname of the file to load from. </param>
        ///-------------------------------------------------------------------------------------------------
        public void Load(String filePath)
        {
            if (filePath == null)
                throw new ArgumentNullException("filePath");

            if (!File.Exists(filePath))
                throw new FileNotFoundException("Unable to locate game list.", filePath);

            using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                StorageHelper.ReadListBegin(stream);

                Name = StorageHelper.ReadString(stream);
                Author = StorageHelper.ReadString(stream);
                Comment = StorageHelper.ReadString(stream);
                Creation = StorageHelper.ReadDate(stream);
                Modification = StorageHelper.ReadDate(stream);
                WriteProtected = StorageHelper.ReadBool(stream);

                int gameCount = StorageHelper.ReadInt(stream);

                SortField = StorageHelper.ReadInt(stream);

                StorageHelper.ReadListEnd(stream);

                // Read games.
                Games.Clear();
                for (int i = 0; i < gameCount; i++)
                    Games.Add(new MalaGame(stream));
            } // End using stream; close.
        }

        #endregion
    }
}
